/*=============================================================================
# FileName    :	control_test.v
# Author      :	author
# Email       :	email@email.com
# Description :	
# Version     :	1.0
# LastChange  :	2019-10-22 10:02:11
# ChangeLog   :	
=============================================================================*/

`timescale  1 ns/1 ps
//`define     DEBUG_VIO

module control_test #
(
    parameter               PROGRAM_256WORD_TIME = 200*2000, // *8ns
    parameter               ERASE_TIME_CNT = 1_000_000_000/8,
    parameter               ADDR_W = 26,
    parameter               DATA_W = 16
)
(
    input                       clk,
    input                       rst,
    /*port*/

    output  reg  [07:00]        flash_cmd,
    output  reg  [ADDR_W-1:00]  flash_addr,     // ???要操作的flash地址

    output  reg                 m_axis_tvalid,
    output  reg                 m_axis_tlast,
    input                       m_axis_tready,
    output  reg  [07:00]        m_axis_tdata
);
`include "../hdl/nor_flash_drive/src/nor_flash_macro.v"


localparam              IDLE       = 0;
localparam              ERASE      = 1;
localparam              ERASE_DLY  = 2;
localparam              WR_COMMAND = 3;
localparam              WR_DATA    = 4;
localparam              WR_DLY     = 5;
localparam              RD_DATA    = 6;
localparam              RD_DLY     = 7;
localparam              RD_STATUS  = 8;
localparam              STATUS_DLY = 9;
localparam              CLR_STATUS = 10;
localparam              OVER       = 11;
(* KEEP = "TRUE" *)reg     [OVER:00]       cs = 'd1, ns = 'd1;
reg     [31:00]         state_cnt, state_cnt_n;

`ifdef USE_ISE
`else
wire     [03:00]         vio_reg;
reg      [03:00]         vio_reg_r0;
wire     [ADDR_W-1:00]   flash_addr_r0;     // ???要操作的flash地址
always @ (posedge clk)
begin
    vio_reg_r0 <= vio_reg;
end
vio_0                       ip_vio
(
    .clk           (  clk           ),
    .probe_out0    (  vio_reg       ),
    .probe_out1    (  flash_addr_r0 )
);
`endif

// synthesis translate_off
reg [127:0] cs_STRING;
always @(*)
begin
    case(1'b1)
        cs[IDLE]: cs_STRING = "IDLE";
        cs[ERASE]: cs_STRING = "ERASE";
        cs[ERASE_DLY]: cs_STRING = "ERASE_DLY";
        cs[WR_COMMAND]: cs_STRING = "WR_COMMAND";
        cs[WR_DATA]: cs_STRING = "WR_DATA";
        cs[WR_DLY]: cs_STRING = "WR_DLY";
        cs[RD_DATA]: cs_STRING = "RD_DATA";
        cs[RD_DLY]: cs_STRING = "RD_DLY";
        cs[RD_STATUS]: cs_STRING = "RD_STATUS";
        cs[STATUS_DLY]: cs_STRING = "STATUS_DLY";
        cs[CLR_STATUS]: cs_STRING = "CLR_STATUS";
        cs[OVER]: cs_STRING = "OVER";
        default: cs_STRING = "XXXX";
    endcase
end
// synthesis translate_on

always @(posedge clk)
begin
    if(rst)
        cs <= 'd1;
    else
        cs <= ns;
end

always @(*)
begin
    ns = 'd0;
    case(1'b1)
        cs[IDLE]:
        begin

`ifdef USE_ISE
            if(state_cnt == 100)
                //ns[ERASE] = 1'b1;
                ns[WR_COMMAND] = 1'b1;
                //ns[RD_DATA] = 1'b1;
                //ns[RD_STATUS] = 1'b1;
                //ns[CLR_STATUS] = 1'b1;
            else
                ns[IDLE] = 1'b1;
`else
            if(vio_reg_r0 == 1)
                ns[ERASE] = 1'b1;
            else if(vio_reg_r0 == 2)
                ns[WR_COMMAND] = 1'b1;
            
            else if(vio_reg_r0 == 3)
                ns[RD_DATA] = 1'b1;
            
            else if(vio_reg_r0 == 4)
                ns[RD_STATUS] = 1'b1;
            else if(vio_reg_r0 == 5)
                ns[CLR_STATUS] = 1'b1;
            else
                ns[IDLE] = 1'b1;
`endif

        end
        cs[ERASE]:
        begin
            if(state_cnt == 4)
                ns[ERASE_DLY] = 1'b1;
            else
                ns[ERASE] = 1'b1;
        end
        cs[ERASE_DLY]:
        begin
            //if(state_cnt == ERASE_TIME_CNT)
            if(state_cnt == 62500000)
                ns[WR_COMMAND] = 1'b1;
            else
                ns[ERASE_DLY] = 1'b1;
        end
        cs[WR_COMMAND]:
        begin
            if(state_cnt == 4)
                ns[WR_DATA] = 1'b1;
            else
                ns[WR_COMMAND] = 1'b1;
        end
        cs[WR_DATA]:
        begin
            if(state_cnt == 255)
                ns[WR_DLY] = 1'b1;
            else
                ns[WR_DATA] = 1'b1;
        end
        cs[WR_DLY]:
        begin
            if(state_cnt == PROGRAM_256WORD_TIME)
                ns[RD_DATA] = 1'b1;
            else
                ns[WR_DLY] = 1'b1;
        end
        cs[RD_DATA]:
        begin
            if(state_cnt == 5)
                ns[RD_DLY] = 1'b1;
            else
                ns[RD_DATA] = 1'b1;
        end
        cs[RD_DLY]:
        begin
            if(state_cnt == PROGRAM_256WORD_TIME)
`ifdef USE_ISE
                ns[RD_DATA] = 1'b1;
`else
                ns[IDLE] = 1'b1;
`endif
            else
                ns[RD_DLY] = 1'b1;
        end
        cs[RD_STATUS]:
        begin
            if(state_cnt == 5)
                ns[STATUS_DLY] = 1'b1;
            else
                ns[RD_STATUS] = 1'b1;
        end
        cs[STATUS_DLY]:
        begin
            if(state_cnt == 100000)
                ns[IDLE] = 1'b1;
            else
                ns[STATUS_DLY] = 1'b1;
        end
        cs[CLR_STATUS]:
        begin
            if(state_cnt == 5)
                ns[IDLE] = 1'b1;
            else
                ns[CLR_STATUS] = 1'b1;
        end
        default:
            ns[IDLE] = 1'b1;
    endcase
end


always @ (posedge clk)
begin
    if(rst)
        state_cnt <= 0;
    else
        state_cnt <= state_cnt_n;
end

always @ (*)
begin
    if(rst)
        state_cnt_n <= 0;
    else if (cs != ns)
        state_cnt_n <= 0;
    else
        state_cnt_n <= state_cnt + 1'b1;
end

always @ (posedge clk)
begin
    if(rst)
        flash_cmd <= 0;
    else if(cs[ERASE])
        flash_cmd <= `FLASH_ERASE_BLOCK;
    else if(cs[WR_COMMAND])
        flash_cmd <= `FLASH_BUFFER_PROGRAM;
    else if(cs[RD_DATA])
        flash_cmd <= `FLASH_READ_PAGE;
    else if(cs[RD_STATUS])
        flash_cmd <= `FLASH_RD_STATUS_REG;
    else if(cs[CLR_STATUS])
        flash_cmd <= `FLASH_CLR_STATUS_REG;
    else
        flash_cmd <= 0;
end

`ifdef USE_ISE
always @ (posedge clk)
begin
    if(rst)
        flash_addr <= 0;
    else if(cs[ERASE])
        flash_addr <= 26'h4000;
    else if(cs[WR_COMMAND])
        flash_addr <= 26'h4000;
    else if(cs[RD_DATA])
        flash_addr <= 26'h4000;
end
`else
always @ (posedge clk)
begin
    if(rst)
        flash_addr <= 0;
    else
        flash_addr <= flash_addr_r0;
end
`endif

//assign                  flash_addr = 0;
//assign                  flash_addr = 20;
//assign                  flash_addr = 20000000;

always @ (posedge clk)
begin
    if(rst)
        m_axis_tvalid <= 0;
    else if(cs[WR_DATA])
        m_axis_tvalid <= 1;
    else
        m_axis_tvalid <= 0;
end

always @ (posedge clk)
begin
    if(rst)
        m_axis_tdata <= 0;
    else if(cs[WR_DATA])
        m_axis_tdata <= state_cnt;
        //m_axis_tdata <= 8'h22;
    else
        m_axis_tdata <= 0;
end

always @ (posedge clk)
begin
    if(rst)
        m_axis_tlast <= 0;
    else if(cs[WR_DATA] & ns[WR_DLY])
        m_axis_tlast <= 1;
    else
        m_axis_tlast <= 0;
end
endmodule
